#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <tokens.h>
#include <keywords.h>
#include <lexer.h>
#define MAXLEN 256

FILE *tape;
char lexeme[MAXLEN];
int  i;
int  linenumber = 1;
int  lookahead;
char szBuffer[128];

void skipspaces(void){
    int  head;
    while (isspace(head = getc(tape))){
      if( head == 10 ) // '\n'
	 linenumber++;
    }
    if (head == '{'){
      while ( (head=getc(tape)) != '}' ){
        if ( head == 10 )
	  linenumber++;
      }
      skipspaces();
      return;
    }
    ungetc(head,tape);
}
/* 
 * id = [a-Z] [0-9 a-Z]* 
 */
int isID(void){
    i = 0;
    lexeme[i] = toupper(getc(tape));
    if (isalpha(lexeme[i])) {
        while (isalnum(lexeme[++i] = toupper(getc(tape))));
        ungetc(lexeme[i], tape);
        lexeme[i] = 0;
        if ( (i = iskeyword(lexeme)) )
            return i;
        return ID;
    }
    ungetc(lexeme[i], tape);
    return 0;
}

int isUINT(void){
    i = 0;
    lexeme[i] = getc(tape);
    if ( (isdigit(lexeme[i])) ) {
        if (lexeme[i] == '0') {
            lexeme[1] = 0;
            return UINT;
        }
        while (isdigit(lexeme[++i] = getc(tape)));
        ungetc(lexeme[i], tape);
        lexeme[i] = 0;
        return UINT;
    }
    ungetc(lexeme[i], tape);
    return 0;
}

int isRELOP(void){
    i = 0;
    switch (lexeme[i] = getc(tape)){
       case '<':
         if ((lexeme[++i] = getc(tape)) == '>'){
	   strcpy(lexeme, "<>");
	   return NEQ;
	 }
	 else if (lexeme[i] == '='){
	   strcpy(lexeme, "<=");
	   return LEQ;
	 }
	 ungetc(lexeme[i], tape);
	 strcpy(lexeme, "<");
	 return '<'; 
       case '>':
         if ((lexeme[++i] = getc(tape)) == '='){
	   strcpy(lexeme, ">=");
	   return GEQ;
	 }
         ungetc(lexeme[i], tape);
	 strcpy(lexeme, ">");
	 return '>';
       case '=':
	 strcpy(lexeme, "=");
	 return '=';
       default:
	 ungetc(lexeme[i], tape);
	 return 0;
    }
}

int isADD(void){
    i = 0;
    if ( (lexeme[i] = getc(tape)) == '+' ||
          lexeme[i] == '-' ){
       lexeme[i+1] = 0;
       return ADD;
    }
    ungetc(lexeme[i], tape);
    return 0; 
}

int isMUL(void){
    i = 0;
    if ( (lexeme[i] = getc(tape)) == '/' ||
          lexeme[i] == '*' ){
       lexeme[i+1] = 0;
       return MUL;
    }
    ungetc(lexeme[i], tape);
    return 0; 
}
#if 0 
// ISTO NAO FUNCIONA CORRETAMENTE
/* float = UINT ('.' digit* enotation? | enotation ) | '.' digit+ enotation?*/
int isNUM(void)
{
    i = 0;
    lexeme[i] = getc(tape);
    if ( lexeme[i] == '.' ){ 
      if ( isdigit(lexeme[++i] = getc(tape)) ){
       while ( isdigit(lexeme[++i] = getc(tape)) );
       ungetc(lexeme[i],tape);
       isenotation(tape);
       lexeme[i] = 0;
       return FLOAT;
      }
      ungetc(lexeme[i--],tape);
    }
    if (isdigit(lexeme[i])) { /*[0-9]*/
        if (lexeme[i] == '0') { /* 0 */
            if (tolower(lexeme[++i] = getc(tape)) == 'x') {
                if (isdigit(lexeme[++i] = getc(tape)) || ('a' <= tolower(lexeme[i]) && 'f' >= tolower(lexeme[i])) ){
                  while (isdigit(lexeme[++i] = getc(tape)) || ('a' <= tolower(lexeme[i]) && 'f' <= tolower(lexeme[i]) ) );
                  ungetc(lexeme[i--], tape);
		  lexeme[i] = 0;
                  return HEXA;
                }
                ungetc(lexeme[i--],tape);
                ungetc(lexeme[i],tape);
                return 0;
            }
            if ( lexeme[i] >= '0' && lexeme[i] < '8' ) {
                while ( (lexeme[++i] = getc(tape)) >= '0' && lexeme[i] < '8' ); 
                ungetc(lexeme[i--], tape);
		lexeme[i] = 0;
                return OCTA;
            }
            if ( lexeme[i]  == '.' ){
              while( isdigit(lexeme[++i]=getc(tape)) );
              ungetc(lexeme[i--],tape);
              isenotation(tape);
	      lexeme[i] = 0;
              return FLOAT;
            }
            ungetc(lexeme[i], tape);
            if ( isenotation(tape) ){
	      lexeme[i] = 0;
              return FLOAT;
	    }
            return UINT;
        }
        /* [1-9] */
        if ( (lexeme[++i] = getc(tape)) == '.' ){
          while( isdigit(lexeme[++i]=getc(tape)) );
          ungetc(lexeme[i--],tape);
          isenotation(tape);
	  lexeme[i] = 0;
          return FLOAT;
        }
        ungetc(lexeme[i],tape);
        if ( isenotation(tape) )
          return FLOAT;

        while (isdigit(lexeme[++i] = getc(tape)));
        ungetc(lexeme[i], tape);
	lexeme[i] = 0;
        return UINT;
    }
    ungetc(lexeme[i], tape);
    return 0;
}
/* 
 * float = UINT ('.' digit* enotation? | enotation ) | '.' digit+ enotation?
 * enotation = 'E' ('+'|'-')? digit+
 */
int isenotation(FILE * tape){
   lexeme[++i] = getc(tape);
   if ( toupper(lexeme[i]) == 'E' ){
       if( (lexeme[++i]=getc(tape)) != '-' || lexeme[i] != '+' )
	 ungetc(lexeme[i--],tape);
       if( isdigit(lexeme[++i]=getc(tape)) ){
         while( isdigit(lexeme[++i]=getc(tape)) );
         ungetc(lexeme[i],tape);
         return EXP;
       }
       ungetc(lexeme[i],tape);
   }
   ungetc(lexeme[i],tape);
   return 0;
}
#else
/*
 * floating = UINT ('.' digit* enotation? | enotation) | '.' digit+ enotation?
 *
 * enotation = 'E' ('+'|'-')? digit+
 *
 */
int isenotation(void){
    lexeme[i] = getc(tape);
    if (lexeme[i] == 'E' || lexeme[i] == 'e') {
        lexeme[++i] = getc(tape);
        if (lexeme[i] == '+' || lexeme[i] == '-')
            lexeme[++i] = getc(tape);
        if (isdigit(lexeme[i])) {
            while (isdigit(lexeme[++i] = getc(tape)));
            ungetc(lexeme[i], tape);
            lexeme[i] = 0;
            return 1;
        }
        fprintf(stderr, "ilegal exponential notation\n");
        exit(-2);
    }
    ungetc(lexeme[i], tape);
    lexeme[i] = 0;
    return 0;
}

int isNUM(void){
    if (isUINT()) {
        if ((lexeme[i] = getc(tape)) == '.') {
            while (isdigit(lexeme[++i] = getc(tape)));
            ungetc(lexeme[i], tape);
            lexeme[i] = 0;
            isenotation();
            return FLOAT;
        }
        ungetc(lexeme[i], tape);
        lexeme[i] = 0;
        if (isenotation())
            return FLOAT;
        return UINT;
    }
    if ((lexeme[i] = getc(tape)) == '.') {
        if (isdigit(lexeme[++i] = getc(tape))) {
            while (isdigit(lexeme[++i] = getc(tape)));
            ungetc(lexeme[i], tape);
            lexeme[i] = 0;
            isenotation();
            return FLOAT;
        }
        ungetc(lexeme[i--], tape);
        ungetc('.', tape);
        return 0;
    }
    ungetc(lexeme[i], tape);
    return 0;
}
#endif
int isASGNM(void){
    i = 0;
    if((lexeme[i++]=getc(tape))==':'){
      if((lexeme[i++]=getc(tape))=='='){
        lexeme[i] = 0;
	return ASSGNMT;
      }
      ungetc(lexeme[--i],tape);
      lexeme[i]=0;
      return lexeme[0];
    }
  ungetc(lexeme[--i],tape);
  return 0;
}

int isDDOT(void){
  i = 0;
  if((lexeme[i++]=getc(tape))=='.'){
      if((lexeme[i++]=getc(tape))=='.'){
        lexeme[i] = 0;
	return DDOT;
      }
      ungetc(lexeme[--i],tape);
      lexeme[i]=0;
      return lexeme[0];
  }
  ungetc(lexeme[--i],tape);
  return 0;
}

int gettoken(void)
{
    int  token;
    skipspaces();
    if ((token = isID()))
        return token;
    if ((token = isNUM()))
        return token;
    if ((token = isRELOP()))
	return token;
    if ((token = isDDOT()))
	return token;
    if ((token = isADD()))
	return token;
    if ((token = isMUL()))
	return token;
    if ((token = isASGNM()))
	return token;
    lexeme[1] = 0;
    return lexeme[0] = getc(tape);
}

void match(int expected)
{
    if (expected == lookahead) {
        lookahead = gettoken();
    } 
    else {
        fprintf(stderr, 
"Token mismatch at line: %d\n"
"You entered: %s "
"Expected was: %s\n",
	   linenumber,
	   pWichKeyword(lookahead),
	   pWichKeyword(expected)
	);
        exit(-1);
    }
}

